package com.ruoyi.water.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.water.domain.Area;
import com.ruoyi.water.domain.AreaAnalyse;
import com.ruoyi.water.domain.Element;
import com.ruoyi.water.domain.MeterAnalyse;
import com.ruoyi.water.mapper.AreaAnalyseMapper;
import com.ruoyi.water.mapper.AreaMapper;
import com.ruoyi.water.mapper.ElementMapper;
import com.ruoyi.water.mapper.MeterAnalyseMapper;
import com.ruoyi.water.service.IAreaAnalyseService;
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.*;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.stream.Collectors;

/**
 * AreaAnalyse 业务层实现（包含子区域流量计算）
 */
@Service
public class AreaAnalyseServiceImpl extends ServiceImpl<AreaAnalyseMapper, AreaAnalyse> implements IAreaAnalyseService {

    @Autowired
    private AreaMapper areaMapper;

    @Autowired
    private ElementMapper elementMapper;

    @Autowired
    private MeterAnalyseMapper meterAnalyseMapper;

    @Override
    public List<AreaAnalyse> calculateAreaDailyFlow(Date startDate, Date endDate) {
        // 转换日期为LocalDate便于处理
        LocalDate startLocalDate = startDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        LocalDate endLocalDate = endDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();

        // 获取所有区域并构建父子关系映射
        List<Area> allAreas = areaMapper.selectList(null);
        Map<Long, List<Area>> parentToChildrenMap = buildParentChildrenMap(allAreas);

        List<AreaAnalyse> results = new ArrayList<>();

        // 遍历每个区域
        for (Area area : allAreas) {
            // 查询当前区域关联的element
            Map<Boolean, List<Integer>> elementMap = getElementMap(area);

            // 遍历日期范围内的每一天
            long days = ChronoUnit.DAYS.between(startLocalDate, endLocalDate);
            for (int i = 0; i <= days; i++) {
                LocalDate currentDate = startLocalDate.plusDays(i);
                Date analyseDate = Date.from(currentDate.atStartOfDay(ZoneId.systemDefault()).toInstant());

                // 1. 计算当前区域自身的当日流量
                double selfWaterVal = calculateSingleAreaDailyUsage(area, currentDate, elementMap);

                // 2. 计算所有直接子区域的当日流量并累加
                double childrenWaterVal = calculateChildrenAreaDailyUsage(
                        area.getId(),
                        currentDate,
                        parentToChildrenMap,
                        allAreas
                );

                // 总流量 = 自身流量 + 所有子区域流量
                double totalWaterVal = selfWaterVal - childrenWaterVal;

                // 创建并保存AreaAnalyse记录
                AreaAnalyse areaAnalyse = new AreaAnalyse();
                areaAnalyse.setAreaId(area.getId().intValue());
                areaAnalyse.setAreaName(area.getAreaName());
                areaAnalyse.setTodayWaterVal(totalWaterVal);
                areaAnalyse.setAnalyseDate(analyseDate);
                areaAnalyse.setRecordTime(new Date());

                // 保存到数据库
                baseMapper.insert(areaAnalyse);
                results.add(areaAnalyse);
            }
        }

        return results;
    }

    /**
     * 计算区域偏差数据（当前、一月前、一年前）
     */
    @Override
    public List<AreaAnalyse> calculateAreaBiasData(Date startDate, Date endDate) {
        // 转换日期为LocalDate便于处理
        LocalDate startLocalDate = startDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        LocalDate endLocalDate = endDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();

        // 获取所有区域（用于获取设定值waterValue）
        List<Area> allAreas = areaMapper.selectList(null);
        Map<Long, Area> areaMap = new HashMap<>();
        for (Area area : allAreas) {
            areaMap.put(area.getId(), area);
        }

        List<AreaAnalyse> resultList = new ArrayList<>();
        long days = ChronoUnit.DAYS.between(startLocalDate, endLocalDate);

        // 遍历日期范围内的每一天
        for (int i = 0; i <= days; i++) {
            LocalDate currentDate = startLocalDate.plusDays(i);
            Date analyseDate = Date.from(currentDate.atStartOfDay(ZoneId.systemDefault()).toInstant());

            // 遍历所有区域处理偏差数据
            for (Area area : allAreas) {
                Integer areaId = area.getId().intValue();
                Long targetWaterValue = area.getWaterValue(); // 区域设定值

                // 1. 查询当前日期的区域分析记录
                AreaAnalyse currentAnalyse = getAreaAnalyseByAreaAndDate(areaId, analyseDate);
                if (currentAnalyse == null) {
                    continue; // 跳过无流量数据的记录
                }

                // 2. 计算当前日期偏差值和偏差比
                calculateCurrentBias(currentAnalyse, targetWaterValue);

                // 3. 处理一月前的数据
                LocalDate oneMonthAgo = currentDate.minusMonths(1);
                Date oneMonthAgoDate = Date.from(oneMonthAgo.atStartOfDay(ZoneId.systemDefault()).toInstant());
                AreaAnalyse monthAgoAnalyse = getAreaAnalyseByAreaAndDate(areaId, oneMonthAgoDate);
                calculateMonthBias(currentAnalyse, monthAgoAnalyse, targetWaterValue);

                // 4. 处理一年前的数据
                LocalDate oneYearAgo = currentDate.minusYears(1);
                Date oneYearAgoDate = Date.from(oneYearAgo.atStartOfDay(ZoneId.systemDefault()).toInstant());
                AreaAnalyse yearAgoAnalyse = getAreaAnalyseByAreaAndDate(areaId, oneYearAgoDate);
                calculateYearBias(currentAnalyse, yearAgoAnalyse, targetWaterValue);

                // 5. 更新记录时间并保存
                currentAnalyse.setRecordTime(new Date());
                baseMapper.updateById(currentAnalyse);
                resultList.add(currentAnalyse);
            }
        }

        return resultList;
    }

    /**
     * 查询指定区域和日期的分析记录
     */
    private AreaAnalyse getAreaAnalyseByAreaAndDate(Integer areaId, Date analyseDate) {
        QueryWrapper<AreaAnalyse> wrapper = new QueryWrapper<>();
        wrapper.eq("areaId", areaId)
                .eq("analyseDate", analyseDate);
        return baseMapper.selectOne(wrapper);
    }

    /**
     * 计算当前日期的偏差值和偏差比
     */
    private void calculateCurrentBias(AreaAnalyse analyse, Long targetValue) {
        if (targetValue == null) {
            return; // 无设定值时不计算偏差
        }

        Double currentValue = analyse.getTodayWaterVal();
        double currentBiasVal = currentValue != null ? currentValue - targetValue : 0 - targetValue;
        analyse.setTodayBiasVal(currentBiasVal);

        // 设定值为0时不计算偏差比
        if (targetValue != 0) {
            double biasPercent = (currentBiasVal / targetValue) * 100;
            analyse.setTodayBiasPercent(biasPercent);
        } else {
            analyse.setTodayBiasPercent(null);
        }
    }

    /**
     * 计算一月前的相关值和偏差
     */
    private void calculateMonthBias(AreaAnalyse currentAnalyse, AreaAnalyse monthAnalyse, Long targetValue) {
        if (monthAnalyse == null) {
            return; // 无历史数据时不处理
        }

        // 一月前的实际值
        currentAnalyse.setMonthWaterVal(monthAnalyse.getTodayWaterVal());

        if (targetValue == null) {
            return;
        }

        // 一月前的偏差值
        Double monthValue = monthAnalyse.getTodayWaterVal();
        double monthBiasVal = monthValue != null ? monthValue - targetValue : 0 - targetValue;
        currentAnalyse.setMonthBiasVal(monthBiasVal);

        // 设定值为0时不计算偏差比
        if (targetValue != 0) {
            double monthBiasPercent = (monthBiasVal / targetValue) * 100;
            currentAnalyse.setMonthBiasPercent(monthBiasPercent);
        } else {
            currentAnalyse.setMonthBiasPercent(null);
        }
    }

    /**
     * 计算一年前的相关值和偏差
     */
    private void calculateYearBias(AreaAnalyse currentAnalyse, AreaAnalyse yearAnalyse, Long targetValue) {
        if (yearAnalyse == null) {
            return; // 无历史数据时不处理
        }

        // 一年前的实际值
        currentAnalyse.setYearWaterVal(yearAnalyse.getTodayWaterVal());

        if (targetValue == null) {
            return;
        }

        // 一年前的偏差值
        Double yearValue = yearAnalyse.getTodayWaterVal();
        double yearBiasVal = yearValue != null ? yearValue - targetValue : 0 - targetValue;
        currentAnalyse.setYearBiasVal(yearBiasVal);

        // 设定值为0时不计算偏差比
        if (targetValue != 0) {
            double yearBiasPercent = (yearBiasVal / targetValue) * 100;
            currentAnalyse.setYearBiasPercent(yearBiasPercent);
        } else {
            currentAnalyse.setYearBiasPercent(null);
        }
    }

    /**
     * 构建父区域到子区域的映射关系
     */
    private Map<Long, List<Area>> buildParentChildrenMap(List<Area> allAreas) {
        Map<Long, List<Area>> parentToChildrenMap = new HashMap<>();
        for (Area area : allAreas) {
            if (area.getParentAreaId() != null) {
                // 为每个父区域ID添加子区域
                parentToChildrenMap.computeIfAbsent(area.getParentAreaId(), k -> new ArrayList<>())
                        .add(area);
            }
        }
        return parentToChildrenMap;
    }

    /**
     * 获取区域关联的element映射（区分firstAreaId和negativeAreaId）
     */
    private Map<Boolean, List<Integer>> getElementMap(Area area) {
        QueryWrapper<Element> elementWrapper = new QueryWrapper<>();
        elementWrapper.eq("firstAreaId", area.getId())
                .or()
                .eq("negativeAreaId", area.getId());
        List<Element> elements = elementMapper.selectList(elementWrapper);

        Map<Boolean, List<Integer>> elementMap = new HashMap<>();
        elementMap.put(true, new ArrayList<>());  // firstAreaId关联的element（加）
        elementMap.put(false, new ArrayList<>()); // negativeAreaId关联的element（减）

        for (Element element : elements) {
            if (element.getFirstAreaId() != null && element.getFirstAreaId().equals(area.getId().intValue())) {
                elementMap.get(true).add(element.getId());
            } else if (element.getNegativeAreaId() != null && element.getNegativeAreaId().equals(area.getId().intValue())) {
                elementMap.get(false).add(element.getId());
            }
        }
        return elementMap;
    }

    /**
     * 计算单个区域在指定日期的流量
     */
    /**
     * 计算单个区域在指定日期的流量
     */
    private double calculateSingleAreaDailyUsage(Area area, LocalDate currentDate, Map<Boolean, List<Integer>> elementMap) {
        Date analyseDate = Date.from(currentDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
        double total = 0.0;

        // 获取当前区域的级别，用于过滤对应级别的元素
        long areaLevel = area.getAreaLevel(); // 假设Area类有getAreaLevel()方法获取区域级别

        // 1. 收集所有需要验证的meterId
        List<Integer> allMeterIds = new ArrayList<>();
        allMeterIds.addAll(elementMap.getOrDefault(true, Collections.emptyList()));
        allMeterIds.addAll(elementMap.getOrDefault(false, Collections.emptyList()));

        // 2. 批量查询所有关联的Element（使用MyBatis Plus默认方法）
        Map<Integer, Element> meterIdToElementMap = new HashMap<>();
        if (!allMeterIds.isEmpty()) {
            QueryWrapper<Element> elementWrapper = new QueryWrapper<>();
            elementWrapper.in("id", allMeterIds);
            List<Element> elements = elementMapper.selectList(elementWrapper);

            // 构建meterId到Element的映射，方便后续查询
            for (Element element : elements) {
                meterIdToElementMap.put(element.getId(), element);
            }
        }

        // 3. 处理需要加的元素（需满足：非空、是监控元素、元素级别与区域级别一致）
        List<Integer> validPlusMeterIds = elementMap.getOrDefault(true, Collections.emptyList()).stream()
                .filter(meterId -> {
                    Element element = meterIdToElementMap.get(meterId);
                    // 新增元素级别与区域级别匹配的判断条件
                    return element != null
                            && element.getIsmonitor()
                            && element.getElemLevel() == areaLevel; // 假设Element类有getElemLevel()方法
                })
                .collect(Collectors.toList());

        if (!validPlusMeterIds.isEmpty()) {
            QueryWrapper<MeterAnalyse> plusWrapper = new QueryWrapper<>();
            plusWrapper.in("meterId", validPlusMeterIds)
                    .eq("analyseDate", analyseDate);
            List<MeterAnalyse> plusMeterAnalyses = meterAnalyseMapper.selectList(plusWrapper);

            for (MeterAnalyse meter : plusMeterAnalyses) {
                if (meter.getTodayUsage() != null) {
                    total += meter.getTodayUsage();
                }
            }
        }

        // 4. 处理需要减的元素（需满足：非空、是监控元素、元素级别与区域级别一致）
        List<Integer> validMinusMeterIds = elementMap.getOrDefault(false, Collections.emptyList()).stream()
                .filter(meterId -> {
                    Element element = meterIdToElementMap.get(meterId);
                    // 新增元素级别与区域级别匹配的判断条件
                    return element != null
                            && element.getIsmonitor()
                            && element.getElemLevel() == areaLevel; // 假设Element类有getElemLevel()方法
                })
                .collect(Collectors.toList());

        if (!validMinusMeterIds.isEmpty()) {
            QueryWrapper<MeterAnalyse> minusWrapper = new QueryWrapper<>();
            minusWrapper.in("meterId", validMinusMeterIds)
                    .eq("analyseDate", analyseDate);
            List<MeterAnalyse> minusMeterAnalyses = meterAnalyseMapper.selectList(minusWrapper);

            for (MeterAnalyse meter : minusMeterAnalyses) {
                if (meter.getTodayUsage() != null) {
                    total -= meter.getTodayUsage();
                }
            }
        }

        return total;
    }


    /**
     * 计算所有直接子区域在指定日期的总流量
     */
    private double calculateChildrenAreaDailyUsage(
            Long parentAreaId,
            LocalDate currentDate,
            Map<Long, List<Area>> parentToChildrenMap,
            List<Area> allAreas) {

        double totalChildrenUsage = 0.0;
        // 获取当前区域的所有直接子区域
        List<Area> children = parentToChildrenMap.getOrDefault(parentAreaId, Collections.emptyList());

        for (Area child : children) {
            // 获取子区域的element映射
            Map<Boolean, List<Integer>> childElementMap = getElementMap(child);
            // 计算子区域自身的当日流量
            double childUsage = calculateSingleAreaDailyUsage(child, currentDate, childElementMap);
            totalChildrenUsage += childUsage;
        }

        return totalChildrenUsage;
    }
}
